Java JavaScript Python C# C C++ Go Kotlin PHP Swift R Ruby TypeScript Scala SQL Perl rust VisualBasic Matlab Julia

Generics → Generic Interfaces

Generics

Generic Interfaces

Generic Interfaces in Java: A Detailed Explanation

Generic interfaces in Java allow you to define interfaces that can work with various data types without sacrificing type safety. This is achieved by using type parameters, typically denoted by ``, ``, `` etc., within the interface declaration. These type parameters act as placeholders for concrete types that will be specified when the interface is implemented.

Benefits of Generic Interfaces

1. Type Safety Eliminates the need for casting and reduces runtime errors associated with type mismatches. The compiler enforces type constraints at compile time. 2. Code Reusability A single generic interface can be used with multiple data types, avoiding code duplication. 3. Improved Readability Makes code cleaner and easier to understand by clearly specifying the intended types.

Example 1: A Simple Generic Interface

Let's create a generic interface `DataContainer` that can hold objects of any type `T`:
Generic interface syntax example interface DataContainer { void setData(T data); T getData(); }

This interface has two methods: `setData` to store data of type `T`, and `getData` to retrieve data of type `T`. Now, we can create concrete implementations for different types
Java generic interfaces example interface DataContainer { void setData(T data); T getData(); } class IntegerContainer implements DataContainer { private Integer data; @Override public void setData(Integer data) { this.data = data; } @Override public Integer getData() { return data; } } class StringContainer implements DataContainer { private String data; @Override public void setData(String data) { this.data = data; } @Override public String getData() { return data; } } public class Main { public static void main(String[] args) { IntegerContainer integerContainer = new IntegerContainer(); integerContainer.setData(10); System.out.println("Integer Container Data: " + integerContainer.getData()); StringContainer stringContainer = new StringContainer(); stringContainer.setData("Hello"); System.out.println("String Container Data: " + stringContainer.getData()); } }

Output

Integer Container Data: 10 String Container Data: Hello
Notice how `IntegerContainer` uses `Integer` as the type argument for `DataContainer`, and `StringContainer` uses `String`. This ensures type safety; you can't accidentally put a `String` into an `IntegerContainer`.

Example 2: Interface with Multiple Type Parameters

Generic interfaces can also have multiple type parameters:
Java Interface example with Multiple Type Parameters interface KeyValuePair { void setKey(K key); K getKey(); void setValue(V value); V getValue(); } class StringIntegerPair implements KeyValuePair { private String key; private Integer value; @Override public void setKey(String key) { this.key = key; } @Override public String getKey() { return key; } @Override public void setValue(Integer value) { this.value = value; } @Override public Integer getValue() { return value; } @Override public String toString() { return "(" + key + ", " + value + ")"; } } public class Main { public static void main(String[] args) { StringIntegerPair pair1 = new StringIntegerPair(); pair1.setKey("apple"); pair1.setValue(1); System.out.println("Pair 1: " + pair1.getKey() + " = " + pair1.getValue()); StringIntegerPair pair2 = new StringIntegerPair(); pair2.setKey("banana"); pair2.setValue(2); System.out.println("Pair 2: " + pair2); KeyValuePair genericPair = new StringIntegerPair(); genericPair.setKey("cherry"); genericPair.setValue(3); System.out.println("Generic Pair: " + genericPair.getKey() + " = " + genericPair.getValue()); } }

Output

Pair 1: apple = 1 Pair 2: (banana, 2) Generic Pair: cherry = 3

Here, `KeyValuePair` represents a key-value pair where `K` is the key type and `V` is the value type. `StringIntegerPair` implements this interface using `String` for keys and `Integer` for values.

Example 3: Bounded Type Parameters

Sometimes you might want to restrict the types that can be used with a generic interface. This is done using bounded type parameters:
Java generics bounded Type Parameters interface NumberProcessor { // T must be a subclass of Number double process(T number); } class DoubleProcessor implements NumberProcessor { @Override public double process(Double number) { return number * 2; } } class IntegerProcessor implements NumberProcessor { @Override public double process(Integer number) { return number + 10; } } public class Main { public static void main(String[] args) { DoubleProcessor doubleProcessor = new DoubleProcessor(); double resultDouble = doubleProcessor.process(5.5); System.out.println("Double Processor Result: " + resultDouble); IntegerProcessor integerProcessor = new IntegerProcessor(); double resultInteger = integerProcessor.process(10); System.out.println("Integer Processor Result: " + resultInteger); // The following line would cause a compile-time error as mentioned in the problem: // class StringProcessor implements NumberProcessor {} } }

Output

Double Processor Result: 11.0 Integer Processor Result: 20.0

In this example, `NumberProcessor` specifies that `T` must be a subclass of `Number`. This ensures that only numeric types can be used with this interface. These examples demonstrate the power and flexibility of generic interfaces in Java. They enable you to write more reusable, type-safe, and maintainable code by abstracting away the specifics of data types while enforcing type correctness. Remember to consider bounded type parameters when you need to constrain the types allowed within your generic interface.

Tutorials